/*
 * Copyright (c) 2014-2015 Luca Agostini, Alessandro Cantini, Alessandro Dignani
 *
 * This file is part of MeteoCal.
 *
 * MeteoCal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package it.polimi.se2.agostini_cantini_dignani.meteocal.business;

import it.polimi.se2.agostini_cantini_dignani.meteocal.entity.WeatherForecast;
import it.polimi.se2.agostini_cantini_dignani.meteocal.util.DateTimeUtils;
import it.polimi.se2.agostini_cantini_dignani.meteocal.util.HttpRequest;
import org.apache.commons.lang3.time.DateUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javax.ejb.Stateless;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class is a parser, so it retrieves information from json responses.
 *
 * @author Luca Agostini <luca1.agostini@mail.polimi.it>
 */
@Stateless
public class WeatherForecastRetrieval {

	private static final Logger LOGGER = Logger.getLogger(WeatherForecastRetrieval.class.getName());

	/**
	 * Retrieves the weather forecast of a a given date in a given place.
	 *
	 * @param place the place of the forecast
	 * @param date  the related event date
	 * @return the weather
	 */
	public WeatherForecast retrieveWeatherForecast(String place, Date date) {
		if (place == null || date == null) {
			throw new IllegalArgumentException();
		}
		Date now = new Date();
		if (DateUtils.isSameDay(date, now)) {
			return retrieveCurrentWeather(place);
		}
		String data = HttpRequest.getWeatherData(place);
		if (data == null) {
			return null;
		}
		WeatherForecast forecast = null;
		try {
			JSONObject jObj = new JSONObject(data);
			JSONArray list = jObj.getJSONArray("list");
			int daysElapsed = DateTimeUtils.distanceInDays(date, now);

			if (daysElapsed <= 0) {
				return null;
			}
			JSONObject forecastJSON = list.getJSONObject(daysElapsed);
			JSONArray weather = forecastJSON.getJSONArray("weather");
			forecast = new WeatherForecast(getString("description", weather.getJSONObject(0)));
			forecast.setTemperature(Float.parseFloat(getString("day", forecastJSON.getJSONObject("temp"))));
			forecast.setIconId(getString("icon", weather.getJSONObject(0)));
		} catch (JSONException e) {
			LOGGER.log(Level.SEVERE, "Error parsing forecast.");
		}

		return forecast;
	}

	/**
	 * Retrieves the list of the next 7 days for a given place.
	 *
	 * @param place the place of the forecast
	 * @return the list of weather forecasts
	 */
	public List<WeatherForecast> retrieveWeeklyForecasts(String place) {
		if (place == null) {
			throw new IllegalArgumentException();
		}
		String data = HttpRequest.getWeatherData(place);
		if (data == null) {
			return null;
		}
		List<WeatherForecast> forecastList = new ArrayList<>();
		try {
			JSONObject jObj = new JSONObject(data);
			JSONArray list = jObj.getJSONArray("list");
			for (int i = 0; i < list.length(); i++) {
				WeatherForecast thisForecast = null;
				JSONObject forecast = list.getJSONObject(i);
				JSONArray weather = forecast.getJSONArray("weather");
				thisForecast = new WeatherForecast(getString("description", weather.getJSONObject(0)));
				thisForecast.setTemperature(Float.parseFloat(getString("day", forecast.getJSONObject("temp"))));
				thisForecast.setIconId(getString("icon", weather.getJSONObject(0)));
				forecastList.add(thisForecast);
			}
		} catch (JSONException e) {
			LOGGER.log(Level.SEVERE, "Error parsing weekly forecasts.");
		}
		return forecastList;
	}

	private WeatherForecast retrieveCurrentWeather(String place) {
		if (place == null) {
			throw new IllegalArgumentException();
		}
		String data = HttpRequest.getCurrentWeather(place);

		WeatherForecast forecast = null;

		JSONObject jObj;
		if (data == null) {
			return null;
		}
		try {
			jObj = new JSONObject(data);
			JSONArray list = jObj.getJSONArray("weather");
			forecast = new WeatherForecast(getString("description", list.getJSONObject(0)));
			forecast.setTemperature(Float.parseFloat(getString("temp", jObj.getJSONObject("main"))));
			forecast.setIconId(getString("icon", list.getJSONObject(0)));
		} catch (JSONException e) {
			LOGGER.log(Level.SEVERE, "Error parsing current weather.");
		}
		return forecast;
	}

	private String getString(String tagName, JSONObject jObj) throws JSONException {
		return jObj.getString(tagName);
	}
}
